// Bristleback plugin - Copyright (c) 2010 bristleback.googlecode.com
// ---------------------------------------------------------------------------
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
// This library is distributed in the hope that it will be useful,
// but without any warranty; without even the implied warranty of merchantability
// or fitness for a particular purpose.
// You should have received a copy of the GNU Lesser General Public License along
// with this program; if not, see <http://www.gnu.org/licenses/lgpl.html>.
// ---------------------------------------------------------------------------
package pl.bristleback.server.bristle.messages;

import org.apache.log4j.Logger;
import org.jwebsocket.api.WebSocketConnector;
import org.jwebsocket.api.WebSocketPacket;
import pl.bristleback.server.bristle.utils.PacketProcessingUtil;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * This class provides thread safe way to collect and send all outbound messages.
 * It is a default implementation of {@link pl.bristleback.server.bristle.messages.MessageDispatcher}.
 * It uses LinkedBlockingQueue, which allows thread safe adding messages by any number of threads using senders.
 * It creates one consumer thread which is waiting for incoming messages.
 * <p/>
 * <p/>
 * Created on: 2010-09-24 22:13:40 <br/>
 *
 * @author Wojciech Niemiec
 */
public class SingleThreadedMessageDispatcher extends AbstractMessageDispatcher {
  private static Logger log = Logger.getLogger(SingleThreadedMessageDispatcher.class.getName());

  private static final long DELAY = 1000; // in milliseconds

  private boolean dispatcherStarted;
  private final BlockingQueue<WebSocketMessage> messages;

  public SingleThreadedMessageDispatcher() {
    messages = new LinkedBlockingQueue<WebSocketMessage>();
  }

  @Override
  public void addMessage(WebSocketMessage message) {
    messages.add(message);
  }

  @Override
  public void dispatchMessages() throws Exception {
    WebSocketMessage message = messages.poll(DELAY, TimeUnit.MILLISECONDS);
    if (message != null) {
      sendMessage(message);
    }
  }

  private void sendMessage(WebSocketMessage message) {
    //todo-wojtek check if creating only one packet object is safe.
    WebSocketPacket packet = PacketProcessingUtil.processTokenToPacket(message.getToken());
    for (WebSocketConnector connector : message.getBroadcastConnectors()) {
      getServer().sendPacket(connector, packet);
    }
  }

  @Override
  public void startDispatching() {
    if (dispatcherStarted) {
      throw new IllegalStateException("Dispatcher already started dispatching");
    }
    Thread dispatcherThread = new Thread(new Dispatcher());
    setDispatcherStarted(true);
    dispatcherThread.start();
  }

  @Override
  public void stopDispatching() {
    if (!dispatcherStarted) {
      throw new IllegalStateException("Dispatcher is not started yet");
    }
    setDispatcherStarted(false);
  }


  private void setDispatcherStarted(boolean dispatcherStarted) {
    this.dispatcherStarted = dispatcherStarted;
  }

  private class Dispatcher implements Runnable {

    public void run() {
      try {
        while (dispatcherStarted) {
          dispatchMessages();
        }
      } catch (Exception e) {
        //nothing
        log.error(e);
      }
    }
  }
}
